package HMM;

import java.util.ArrayList;


/**
 * @uml.dependency   supplier="HMM.HMMCommonFunctions"
 */
public class DoubleMatrix {
	
	protected double[][] _array;
	
	protected boolean _predecessorsComputed = false;
	
	protected boolean _emittersComputed = false;
	
	protected ArrayList<ArrayList<Integer>> _precedingStates = new ArrayList<ArrayList<Integer>>();
	
	protected ArrayList<ArrayList<Integer>> _emittingStates = new ArrayList<ArrayList<Integer>>();
	
	public DoubleMatrix(int rows, int cols, double initVal){
		_array = new double[rows][cols];
		
		for (int i = 0; i < rows; i++){
			for (int j = 0; j < cols; j++){
				_array[i][j] = initVal;
			}
		}	
	}
	
	public DoubleMatrix(int rows, int cols){
		_array = new double[rows][cols];
	}
	
	public double get(int i, int j) {
		return _array[i][j];
	}
	
	public void set(int i, int j, double val) {
		_array[i][j] = val;
	}
	
	public int getRowNr(){
		return _array.length;
	}
	
	public int getColNr(){
		return _array[0].length;
	}
	
	public DoubleMatrix add(DoubleMatrix otherMx) {
		for (int i = 0; i < _array.length; i++){
			for (int j = 0; j < _array[0].length; j++){
				_array[i][j] = _array[i][j] + otherMx.get(i,j);
			}
		}
		return this;
	}
	
	public DoubleMatrix scalarTimes(double c) {
		for (int i = 0; i < _array.length; i++){
			for (int j = 0; j < _array[0].length; j++){
				_array[i][j] = _array[i][j] * c;
			}
		}
		return this;
	}
	
	public DoubleMatrix increment(int i, int j, double incr) {
		_array[i][j] += incr; 
		return this;
	}
	
	public DoubleMatrix log() {
		for (int i = 0; i < _array.length; i++){
			for (int j = 0; j < _array[0].length; j++){
				_array[i][j] = Math.log(_array[i][j]);
			}
		}
		return this;
	}
	
	public void computePrecedingStates() {
		if (_predecessorsComputed) return;
		_predecessorsComputed = true;
		
		for (int l = 0; l < _array.length; l++) {
			_precedingStates.add(l, new ArrayList<Integer>());
			for (int k = 0; k < _array.length; k++) {
				if (_array[l][k]!=Double.NEGATIVE_INFINITY) _precedingStates.get(l).add(k);
			}
		}
	}
	
	public void computeEmittingStates() {
		if (_emittersComputed) return;
		_emittersComputed = true;
		
		for (int l = 0; l < _array[0].length; l++) {
			_emittingStates.add(l, new ArrayList<Integer>());
			for (int k = 0; k < _array.length; k++) {
				if (_array[k][l]!=Double.NEGATIVE_INFINITY) _emittingStates.get(l).add(k);
			}
		}
	}
	
	public ArrayList<Integer> getPrecedingStates(int state) {
		computePrecedingStates();
		return _precedingStates.get(state);
	}
	
	public ArrayList<Integer> getEmittingStates(int emission) {
		computeEmittingStates();
		return _emittingStates.get(emission);
	}
	
}